from django import forms
from django.core.exceptions import ValidationError
from django.db.models.fields.files import FieldFile

from .engine.review import *
from .models import *

from .util.util import *


class ReviewProfileForm(forms.ModelForm):
    PROFILE_CREATE = 1
    PROFILE_UPDATE = 2

    class Meta:
        model = ReviewProfile
        fields = '__all__'
        widgets = {
            'review_repository': forms.Select(
                choices=get_repository_name_name_tuple(),
            ),
            'review_target_people': forms.SelectMultiple(choices=get_people_name_name_tuple()),
            'review_target_groups': forms.SelectMultiple(choices=get_group_name_name_tuple()),
            'review_testing_done': forms.Textarea(attrs={'cols': 80, 'rows': 20}),
            # 'review_branch': forms.SelectMultiple(choices=get_branch_name_name_tuple()),
            'review_description_template': forms.Textarea(
                attrs={'cols': 80, 'rows': 20}),
            'user': forms.HiddenInput(),
        }

    def __init__(self, opera_type, *args, **kwargs):
        self.opera_type = opera_type
        super(ReviewProfileForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        profile = super(ReviewProfileForm, self).save(commit=False)
        profile.user = self.cleaned_data.get('user')
        review_branch_list = self.cleaned_data.get(
            'review_branch').strip('[]').split(',')
        profile.review_branch = ','.join([
            branch.strip().strip("'") for branch in review_branch_list
        ])
        review_target_people_list = self.cleaned_data.get(
            'review_target_people').strip('[]').split(',')
        profile.review_target_people = ','.join([
            people.strip().strip("'") for people in review_target_people_list
        ])
        review_target_group_list = self.cleaned_data.get(
            'review_target_groups').strip('[]').split(',')
        profile.review_target_groups = ','.join([
            group.strip().strip("'") for group in review_target_group_list
        ])
        if commit:
            profile.save()
        return profile

    def clean(self):
        cleaned_data = super(ReviewProfileForm, self).clean()
        profile_name = cleaned_data.get('profile_name')
        if self.opera_type == self.PROFILE_UPDATE and profile_name != self.instance.profile_name:
            if ReviewProfile.objects.filter(
                    user_id=cleaned_data.get('user').id,
                    profile_name=profile_name
            ).exists():
                raise ValidationError(str.format(
                    f"A profile named {profile_name} already exists"
                ))


class ReviewUserInfoForm(forms.ModelForm):
    # TODO: Add 'user' ModelChoiceField for it's corresponding foreign field in model here ... Some reference:
    #  https://stackoverflow.com/questions/1057252/how-do-i-access-the-request-object-or-any-other-variable-in-a
    #  -forms-clean-met https://stackoverflow.com/questions/24643074/access-request-object-from-class-based-view
    #  file:///E:/files/django/ref/forms/fields.html#django.forms.ModelChoiceField

    class Meta:
        model = ReviewUser
        exclude = ['review_cookie_file']
        widgets = {
            'user': forms.HiddenInput(),
        }

    def save(self, commit=True):
        info = super(ReviewUserInfoForm, self).save(commit=False)
        info.user = self.cleaned_data.get('user')
        if commit:
            if not info.review_cookie_file:
                info.review_cookie_file = f'.review/cookies/{info.user.username}'
            info.save()
        return info


class ReviewPresettingForm(forms.Form):
    review_num = forms.IntegerField(max_value=10, min_value=1)


class ReviewPublicForm(forms.ModelForm):
    """ Review create/update view use the same form """
    REVIEW_CREATE = 1
    REVIEW_UPDATE = 2

    need_public = forms.CharField(
        widget=forms.HiddenInput(attrs={
            'class': 'class-hidden-need-public'
        })
    )

    class Meta:
        model = ReviewRecord
        exclude = ['review_group', 'review_abs_url', 'review_profile', 'ship_it_count', 'review_id', 'commit_id']
        # widgets = {
        #     'review_testing_done': forms.Textarea(attrs={'cols': 80, 'rows': 20}),
        #     'review_description': forms.Textarea(
        #         attrs={'cols': 80, 'rows': 20}),
        #     'user': forms.HiddenInput(),
        #     'review_id': forms.HiddenInput(),
        #     'review_summary': forms.TextInput(attrs={'required': True}),
        #     'review_change_description': forms.HiddenInput(),
        #     'public': forms.HiddenInput(),
        # }

    def __init__(self, *args, **kwargs):
        self.opera_type = pop_kwargs(kwargs, 'opera_type')
        super(ReviewPublicForm, self).__init__(*args, **kwargs)
    #     if not self.instance.review_id or self.instance.review_id == 0:
    #         # create if no review_id
    #         self.opera_type = ReviewPublicForm.REVIEW_CREATE
    #     if self.opera_type == ReviewPublicForm.REVIEW_UPDATE:
    #         self.fields['review_change_description'] = forms.CharField(
    #             widget=forms.Textarea(attrs={'cols': 80, 'rows': 10}))

    def save(self, commit=True):
        review = super(ReviewPublicForm, self).save(commit=False)
        review.review_id = self.cleaned_data.get('review_id')
        review.review_abs_url = self.cleaned_data.get('review_abs_url')
        if commit:
            review.save()
        return review

    def clean(self):
        cleaned_data = super(ReviewPublicForm, self).clean()
        review_summary = cleaned_data.get('review_summary')
        review_target_people = cleaned_data.get('review_target_people')
        review_target_groups = cleaned_data.get('review_target_groups')
        review_description = cleaned_data.get('review_description')
        if self.instance.public is False and not review_summary or str(review_summary).isspace():
            raise ValidationError('Review summary should not be empty.')

        if not validate_str([review_target_people, review_target_groups]):
            raise ValidationError('Please fill people or groups')

        if self.instance.public is False and not validate_str(review_description):
            raise ValidationError('Must have a description.')

        if self.instance.review_id and self.instance.review_id != 0:
            cleaned_data.update({'review_id': self.instance.review_id})
        # We must fill cleaned_data with initial instance for review-creating.
        kws = cleaned_data.copy()

        if self.opera_type == ReviewPublicForm.REVIEW_CREATE:
            kws.update({
                'review_profile': self.instance.review_profile
            })
        final_patch = cleaned_data.get('final_patch')
        if type(final_patch) == FieldFile and self.opera_type == ReviewPublicForm.REVIEW_UPDATE:
            kws.update({
                'final_patch': None,
            })
        # Use review engine to post review here ...
        need_public = True if int(cleaned_data.get('need_public')) == 1 else False
        if self.opera_type == ReviewPublicForm.REVIEW_CREATE:
            _, review_request = ReviewClient(
                kws).create_draft(public=need_public)
        else:
            if not cleaned_data.get('review_id'):
                raise BaseException
            _, review_request = ReviewClient(
                kws).update_draft(public=need_public)

        if review_request:
            kws = {
                'review_id': review_request.id,
                'review_abs_url': review_request.absolute_url
            }
            # update public status to database in save
            if need_public:
                push_kwargs(kws, {'public': True})
            cleaned_data.update(kws)
        else:
            raise ValidationError(str.format(
                f"Create review failed!"
            ))

        return cleaned_data


class ReviewPublicFormSet(forms.BaseModelFormSet):
    ...


# More about django form class: file:///D:/Files/django/topics/forms/index.html#more-about-django-form-classes
# Binding uploaded files: to form: file:///D:/Files/django/ref/forms/api.html#binding-uploaded-files
class ReviewForm(forms.ModelForm):
    class Meta:
        model = ReviewRecord
        exclude = ['review_id', 'review_abs_url', 'review_branch', 'review_group', 'ship_it_count',
                   'review_summary', 'review_testing_done', 'review_description', 'public',
                   'review_target_groups', 'review_target_people', 'review_change_description', 'commit_id', 'bugs']
        widgets = {
            'user': forms.HiddenInput(),
            'review_profile': forms.Select()
        }

    def __init__(self, *args, **kwargs):
        review_profile_list = pop_kwargs(kwargs, 'review_profile_list')
        super(ReviewForm, self).__init__(*args, **kwargs)
        if review_profile_list:
            self.fields['review_profile'] = forms.ChoiceField(choices=[
                (profile.id, profile.__str__()) for profile in review_profile_list
            ])

    def save(self, commit=True):
        review = super(ReviewForm, self).save(commit=False)
        review.user = self.cleaned_data.get('user')
        profile = self.cleaned_data.get('review_profile')
        review.review_branch = profile.review_branch
        review.review_description = profile.review_description_template
        review.review_testing_done = profile.review_testing_done
        review.review_target_people = profile.review_target_people
        review.review_target_groups = profile.review_target_groups

        if commit:
            review.save()
        return review

    def clean(self):
        cleaned_data = super(ReviewForm, self).clean()

        return cleaned_data


class ReviewFormSet(forms.BaseModelFormSet):
    def __init__(self, *args, **kwargs):
        super(ReviewFormSet, self).__init__(*args, **kwargs)
        self._customer_data = {}

    def set_customer_data(self, data: dict):
        self._customer_data.update(data)

    def get_customer_data(self, key):
        return self._customer_data[key]

    def save(self, commit=True):
        instance_list = super(ReviewFormSet, self).save(commit=False)
        review_group = ReviewRecordGroup(user=self.cleaned_data[0]['user'])
        review_group.save()
        self.set_customer_data({'review_group_id': review_group.id})
        for instance in instance_list:
            instance.review_group = review_group
            instance.save()
        return instance_list
